﻿using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using Kaesoft.Hospedaje.Common;
using Kaesoft.Hospedaje.Entities;
using Kaesoft.Hospedaje.Proxy;
using Kaesoft.Hospedaje.Proxy.ParametrizacionReference;

namespace Kaesoft.Hospedaje.Admin
{
    public class AdministracionParametrosCatalogosViewModel : ViewModelBase
    {
        #region Variables
        private ObservableCollection<Parametro> _listaParametros;
        private ObservableCollection<EstructuraCatalogo> _listaTipos;
        private ObservableCollection<Catalogo> _listaCatalogos;
        
        internal List<int> _parametrosSeleccionados = new List<int>();
        internal List<int> _tiposSeleccionados = new List<int>();
        internal List<int> _catalogosSeleccionados = new List<int>();
        private bool _enabledEliminarParametros = false;
        private bool _enabledEliminarTipos = false;
        private bool _enabledEliminarCatalogos = false;
        private bool _enabledGrabar;
        private EstructuraCatalogo _tipoSeleccionado;

        private RelayCommand _nuevoComand;
        private RelayCommand _eliminarCommand;
        #endregion

        #region Propiedades
        /// <summary>
        /// Habilitar / deshabilitar el botón + en catálogos
        /// </summary>
        public bool EnabledNuevoCatalogo
        {
            get
            {
                return TipoSeleccionado != null && TipoSeleccionado.idEstructuraCatalogo != 0;
            }
        }

        /// <summary>
        /// Lista para los combos en catalogos padres
        /// </summary>
        public List<CatalogoSummary> ListaCatalogoPadre
        {
            get
            {
                if (TipoSeleccionado == null || TipoSeleccionado.codigoPadre == null)
                    return null;

                return Caching.Instancia.Catalogos(((TipoCatalogo)(TipoSeleccionado.codigoPadre.Value))).Where(cat => cat.Codigo > 0).ToList();
            }
        }

        /// <summary>
        /// Tipo de catálogo seleccionado para obtener los catálogos hijos
        /// </summary>
        public EstructuraCatalogo TipoSeleccionado
        {
            get
            {
                if (_tipoSeleccionado == null)
                    return _tipoSeleccionado;

                return ListaTipos != null ? ListaTipos.Where(tipo => tipo.idEstructuraCatalogo == _tipoSeleccionado.idEstructuraCatalogo).FirstOrDefault() : null;
            }
            set
            {
                if (value == null)
                {
                    _tipoSeleccionado = null;
                    OnPropertyChanged("TipoSeleccionado");
                    ListaCatalogos = null;
                }
                else if (_tipoSeleccionado == null || value.idEstructuraCatalogo != _tipoSeleccionado.idEstructuraCatalogo)
                {
                    _tipoSeleccionado = value;

                    if (value != null)
                        Procesando = true;
                        ProxyParametrizacion.ObtenerCatalogosAsync(value.codigo, ev => ObtenerCatalogosCompleted(null, ev));

                    OnPropertyChanged("TipoSeleccionado");
                }

                OnPropertyChanged("EnabledNuevoCatalogo");
                OnPropertyChanged("ListaCatalogoPadre");
            }
        }

        /// <summary>
        /// Habilitar el botón grabar
        /// </summary>
        public bool EnabledGrabar
        {
            get
            {
                return _enabledGrabar;
            }
            set
            {
                if (_enabledGrabar != value)
                {
                    _enabledGrabar = value;
                    if (BarraTareasViewModel != null)
                        BarraTareasViewModel.IsEnableGuardar = value;
                    OnPropertyChanged("EnabledGrabar");
                }
            }
        }

        /// <summary>
        /// para eliminar parametros habilitado?
        /// </summary>
        public bool EnabledEliminarParametros
        {
            get
            {
                return _enabledEliminarParametros;
            }
            set
            {
                if (_enabledEliminarParametros != value)
                {
                    _enabledEliminarParametros = value;
                    OnPropertyChanged("EnabledEliminarParametros");
                }
            }
        }

        /// <summary>
        /// para eliminar tipos habilitado?
        /// </summary>
        public bool EnabledEliminarTipos
        {
            get
            {
                return _enabledEliminarTipos;
            }
            set
            {
                if (_enabledEliminarTipos != value)
                {
                    _enabledEliminarTipos = value;
                    OnPropertyChanged("EnabledEliminarTipos");
                }
            }
        }

        /// <summary>
        /// para eliminar catalogos habilitado?
        /// </summary>
        public bool EnabledEliminarCatalogos
        {
            get
            {
                return _enabledEliminarCatalogos;
            }
            set
            {
                if (_enabledEliminarCatalogos != value)
                {
                    _enabledEliminarCatalogos = value;
                    OnPropertyChanged("EnabledEliminarCatalogos");
                }
            }
        }

        public RelayCommand NuevoCommand { get { return _nuevoComand ?? (_nuevoComand = new RelayCommand(CrearNuevo)); } }
        public RelayCommand EliminarCommand { get { return _eliminarCommand ?? (_eliminarCommand = new RelayCommand(Eliminar)); } }

        /// <summary>
        /// Lista de parametros del sistema
        /// </summary>
        public ObservableCollection<Parametro> ListaParametros
        {
            get
            {
                return _listaParametros;
            }
            set
            {
                if (_listaParametros != value)
                {
                    _listaParametros = value;

                    if (_listaParametros != null)
                        foreach (var param in _listaParametros)
                        {
                            ((INotifyPropertyChanged)param).PropertyChanged += AdministracionParametrosCatalogosViewModel_PropertyChanged;
                        }

                    OnPropertyChanged("ListaParametros");
                }
            }
        }

        /// <summary>
        /// Lista de tipos de catálogo del sistema
        /// </summary>
        public ObservableCollection<EstructuraCatalogo> ListaTipos
        {
            get
            {
                return _listaTipos;
            }
            set
            {
                if (_listaTipos != value)
                {
                    _listaTipos = value;

                    if (_listaTipos != null)
                        foreach (var tipo in _listaTipos)
                        {
                            ((INotifyPropertyChanged)tipo).PropertyChanged += AdministracionParametrosCatalogosViewModel_PropertyChanged;
                        }

                    OnPropertyChanged("ListaTipos");
                }
            }
        }

        /// <summary>
        /// Lista de catálogos del sistema
        /// </summary>
        public ObservableCollection<Catalogo> ListaCatalogos
        {
            get
            {
                return _listaCatalogos;
            }
            set
            {
                if (_listaCatalogos != value)
                {
                    _listaCatalogos = value;

                    if (_listaCatalogos != null)
                        foreach (var catalogo in _listaCatalogos)
                        {
                            ((INotifyPropertyChanged)catalogo).PropertyChanged += AdministracionParametrosCatalogosViewModel_PropertyChanged;
                        }

                    OnPropertyChanged("ListaCatalogos");
                }
            }
        }
        #endregion

        #region Eventos
        public event System.EventHandler RefrescarItems;
        #endregion

        #region Constructor
        /// <summary>
        /// Crea una instancia de AdministracionParametrosCatalogosViewModel
        /// </summary>
        public AdministracionParametrosCatalogosViewModel()
        {
            if (!Design.IsInDesignModeStatic)
            {
                MessageBoxWindow = new MessageWindowView();

                BarraTareasViewModel = new BarraTareasViewModel();
                BarraTareasViewModel.IsVisibleGuardar = true;
                BarraTareasViewModel.IsVisibleCancelar = true;
                BarraTareasViewModel.IsEnableCancelar = true;
                BarraTareasViewModel.BotonTareaClick += BotonOperacionClick;
                Procesando = true;
                ProxyParametrizacion.ObtenerParametrosSistemaAsync(ev => ObtenerParametrosSistemaCompleted(null, ev));
                ProxyParametrizacion.ObtenerTipoCatalogosAsync(ev => ObtenerTipoCatalogosCompleted(null, ev));
            }
        }
        #endregion

        #region Metodos Publicos
        #endregion

        #region Metodos Privados
        /// <summary>
        /// Boton presionado en barra de tareas
        /// </summary>
        /// <param name="sender">Caller</param>
        /// <param name="e">Args</param>
        void BotonOperacionClick(object sender, EventArgs<string> e)
        {
            switch (e.Data)
            {
                case "Guardar":
                    Grabar(null);
                    break;
                case "Cancelar":
                    ErrorList.Clear();
                    IsDirty = false;
                    EnabledGrabar = false;
                    ProxyParametrizacion.ObtenerParametrosSistemaAsync(ev => ObtenerParametrosSistemaCompleted(null, ev));
                    ProxyParametrizacion.ObtenerTipoCatalogosAsync(ev => ObtenerTipoCatalogosCompleted(null, ev));
                    break;
            }
        }

        /// <summary>
        /// Habilitar el boton grabar
        /// </summary>
        void AdministracionParametrosCatalogosViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            EnabledGrabar = true;
            IsDirty = true;
        }

        /// <summary>
        /// Ejecutar el comando Nuevo
        /// </summary>
        /// <param name="parameter">Tipo de objeto</param>
        private void CrearNuevo(object parameter)
        {
            switch (parameter.ToString())
            {
                case "NuevoParametro":
                    var parametro = new Parametro();
                    ((INotifyPropertyChanged)parametro).PropertyChanged += AdministracionParametrosCatalogosViewModel_PropertyChanged;
                    if (ListaParametros == null)
                        ListaParametros = new ObservableCollection<Parametro>();
                    ListaParametros.Add(parametro);
                    break;
                case "NuevoTipo":
                    var tipo = new EstructuraCatalogo();
                    ((INotifyPropertyChanged)tipo).PropertyChanged += AdministracionParametrosCatalogosViewModel_PropertyChanged;
                    if (ListaTipos == null)
                        ListaTipos = new ObservableCollection<EstructuraCatalogo>();
                    ListaTipos.Add(tipo);
                    break;
                case "NuevoCatalogo":
                    var catalogo = new Catalogo();
                    catalogo.codigoEstructura = TipoSeleccionado.codigo;
                    catalogo.codigoEstructuraPadre = TipoSeleccionado.codigoPadre;
                    ((INotifyPropertyChanged)catalogo).PropertyChanged += AdministracionParametrosCatalogosViewModel_PropertyChanged;
                    if (ListaCatalogos == null)
                        ListaCatalogos = new ObservableCollection<Catalogo>();
                    ListaCatalogos.Add(catalogo);
                    break;
            }

            IsDirty = true;
        }

        /// <summary>
        /// Grabar datos
        /// </summary>
        /// <param name="parameter">Null</param>
        private void Grabar(object parameter)
        {
            ErrorList.Clear();

            List<Parametro> parametrosPendientes = null;
            List<Catalogo> catalogosPendientes = null;

            //Parametros
            if (ListaParametros != null)
            {
                parametrosPendientes = ListaParametros.Where(param => param.ChangeTracker.State != ObjectState.Unchanged).ToList();
                parametrosPendientes.ForEach(param =>
                {
                    var errorList = param.Validator.ValidateAll();
                    errorList.Aggregate(ErrorList, (lista, error) => { lista.Add(error); return lista; });
                });
            }

            //Catálogos
            if (ListaCatalogos != null)
            {
                catalogosPendientes = ListaCatalogos.Where(catal => catal.ChangeTracker.State != ObjectState.Unchanged).ToList();
                catalogosPendientes.ForEach(catal =>
                {
                    var errorList = catal.Validator.ValidateAll();
                    errorList.Aggregate(ErrorList, (lista, error) => { lista.Add(error); return lista; });
                });
            }

            if (ErrorList.Count > 0)
            {
                if (RefrescarItems != null)
                    RefrescarItems(null, null);
                return;
            }

            Procesando = true;

            if (parametrosPendientes != null && parametrosPendientes.Count > 0)
                ProxyParametrizacion.GrabarParametroSistemaAsync(parametrosPendientes, ev => GrabarParametroSistemaCompleted(null, ev));

            if (catalogosPendientes != null && catalogosPendientes.Count > 0)
                ProxyParametrizacion.GrabarCatalogoAsync(catalogosPendientes, ev => GrabarCatalogoCompleted(null, ev));
        }

        /// <summary>
        /// Ejecutar el comando eliminar
        /// </summary>
        /// <param name="parameter">Tipo de objeto</param>
        private void Eliminar(object parameter)
        {
            MessageWindowViewModel msgWindowViewModel = new MessageWindowViewModel("Está seguro de borrar los elementos seleccionados? Perderá también los cambios en los elementos no guardados.",
                                                                                   MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            MessageBoxWindow.DataContext = msgWindowViewModel;
            msgWindowViewModel.Closing += (msgsender, ev) =>
            {
                MessageBoxWindow.Close();
                if (ev.Data != MessageBoxResult.Yes) return;

                Procesando = true;

                switch (parameter.ToString())
                {
                    case "EliminarParametros":
                        EliminarParametros();
                        break;
                    case "EliminarTipos":
                        EliminarTipos();
                        break;
                    case "EliminarCatalogos":
                        EliminarCatalogos();
                        break;
                }
            };
            MessageBoxWindow.ShowDialog();
        }

        /// <summary>
        /// Eliminar parametros seleccionados
        /// </summary>
        private void EliminarParametros()
        {
            var list = (from p in ListaParametros
                        where _parametrosSeleccionados.Contains(p.idParametro)
                        select p).Select(param =>
                        {
                            param.borrado = true;
                            return param;
                        }).ToList();

            ProxyParametrizacion.GrabarParametroSistemaAsync(list.Where(param => param.idParametro != 0).ToList(), ev => GrabarParametroSistemaCompleted(null, ev));
        }

        /// <summary>
        /// Completar llamada async a GrabarParametroSistema
        /// </summary>
        /// <param name="sender">Caller</param>
        /// <param name="e">Args</param>
        private void GrabarParametroSistemaCompleted(object sender, AsyncCompletedEventArgs e)
        {
            Procesando = false;
            if (e.Error == null)
            {
                Procesando = true;
                ProxyParametrizacion.ObtenerParametrosSistemaAsync(ev => ObtenerParametrosSistemaCompleted(null, ev));
                IsDirty = false;
            }
        }

        /// <summary>
        /// Completar la llamada async a ObtenerParametrosSistema
        /// </summary>
        /// <param name="sender">Caller</param>
        /// <param name="e">Args</param>
        private void ObtenerParametrosSistemaCompleted(object sender, ObtenerParametrosSistemaCompletedEventArgs e)
        {
            if (e.Error == null)
                ListaParametros = new ObservableCollection<Parametro>(e.Result);
            Procesando = false;
            _parametrosSeleccionados.Clear();
            EnabledGrabar = false;
            EnabledEliminarParametros = false;
        }

        /// <summary>
        /// Completar la llamada async a ObtenerTipoCatalogos
        /// </summary>
        /// <param name="sender">Caller</param>
        /// <param name="e">Args</param>
        private void ObtenerTipoCatalogosCompleted(object sender, ObtenerTipoCatalogosCompletedEventArgs e)
        {
            if (e.Error == null)
                ListaTipos = new ObservableCollection<EstructuraCatalogo>(e.Result);
            Procesando = false;
            _tiposSeleccionados.Clear();
            EnabledGrabar = false;
            EnabledEliminarTipos = false;
        }

        /// <summary>
        /// Eliminar tipo de catalogos
        /// </summary>
        private void EliminarTipos()
        {
            var list = (from t in ListaTipos
                        where _tiposSeleccionados.Contains(t.idEstructuraCatalogo)
                        select t).Select(tipo =>
                        {
                            tipo.borrado = true;
                            return tipo;
                        }).ToList();

            ProxyParametrizacion.GrabarTipoCatalogoAsync(list.Where(tipo => tipo.idEstructuraCatalogo != 0).ToList(), ev => GrabarTipoCatalogoCompleted(null, ev));
        }

        /// <summary>
        /// Completar llamada async a GrabarTipoCatalogo
        /// </summary>
        /// <param name="sender">Caller</param>
        /// <param name="e">Args</param>
        private void GrabarTipoCatalogoCompleted(object sender, AsyncCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                ProxyParametrizacion.ObtenerTipoCatalogosAsync(ev => ObtenerTipoCatalogosCompleted(null, ev));
                IsDirty = false;
            }
        }

        /// <summary>
        /// Completar llamada async a ObtenerCatalogos
        /// </summary>
        /// <param name="sender">Caller</param>
        /// <param name="e">Args</param>
        private void ObtenerCatalogosCompleted(object sender, ObtenerCatalogosCompletedEventArgs e)
        {
            if (e.Error == null)
                ListaCatalogos = new ObservableCollection<Catalogo>(e.Result);
            Procesando = false;
            _catalogosSeleccionados.Clear();
            EnabledEliminarCatalogos = false;
        }

        /// <summary>
        /// Completar llamada async a GrabarCatalogo
        /// </summary>
        /// <param name="sender">Caller</param>
        /// <param name="e">Args</param>
        private void GrabarCatalogoCompleted(object sender, AsyncCompletedEventArgs e)
        {
            if (e.Error == null && TipoSeleccionado != null)
            {
                ProxyParametrizacion.ObtenerCatalogosAsync(TipoSeleccionado.codigo, ev => ObtenerCatalogosCompleted(null, ev));
                EnabledGrabar = false;
                IsDirty = false;
            }
        }

        /// <summary>
        /// Eliminar catalogos
        /// </summary>
        private void EliminarCatalogos()
        {
            var list = (from c in ListaCatalogos
                        where _catalogosSeleccionados.Contains(c.idCatalogo)
                        select c).Select(catalogo =>
                        {
                            catalogo.borrado = true;
                            return catalogo;
                        }).ToList();

            ProxyParametrizacion.GrabarCatalogoAsync(list.Where(catal => catal.idCatalogo != 0).ToList(), ev => GrabarCatalogoCompleted(null, ev));
        }
        #endregion
    }
}